#ifndef GLOBAL_H
#define GLOBAL_H
#include <QDate>
#include <QTime>
#include <QStringList>
#include <QDataStream>

#define STUDY_DB_NAME "StudyDatabase.sqlite"
#define LOG_DB_NAME "LogDatabase.sqlite"
#define STUDY_DB_CONNECTION_NAME "STUDYDB"
#define LOG_DB_CONNECTION_NAME "LOGDB"
#define WLIST_DB_NAME "WlistDatabase.sqlite"
#define WLIST_DB_CONNECTION_NAME "WLISTDB"

#define RAW_IMAGE_PREFIX "RW"
#define PRESENT_IMAGE_PREFIX "PR"
#define REPORT_PREFIX "SR"


// Keys of QSettings
#define DETECTOR_SDK_LOCATION "DETECTORSDKLOCATION"
#define IMAGE_DB_LOCATION "IMAGEDBLOCATION"
#define LOG_DB_LOCATION "LOGDBLOCATION"
#define STUDY_IMPORT_FOLDER "STUDYIMPORTFOLDER"
#define STUDY_IMPORT_FILE "STUDYIMPORTFILE"
#define STAT_EXPORT_FOLDER "STATEXPORTFOLDER"
#define LOG_EXPORT_FOLDER "LOGEXPORTFOLDER"
#define ANNO_TEXT_FONT "ANNOTEXTFONT"

#define MAGNIFIER_SIZE 300
#define MAGNIFIER_FACTOR "MAGNIFIERFACTOR"
#define OPEN_FILEPATH "OPENFILEPATH"
#define SAVE_FILEPATH "SAVEFILEPATH"

#define INCH_MM_RATIO 25.40
#define DATE_DICOM_FORMAT "yyyyMMdd"
#define TIME_DICOM_FORMAT "hhmmss"
#define DATETIME_DICOM_FORMAT "yyyyMMddhhmmss"
#define SQLITE_DATETIME_FORMAT "yyyy-MM-dd hh:mm:ss"
#define SQLITE_DATE_FORMAT "yyyy-MM-dd"
#define SQLITE_TIME_FORMAT "hh:mm:ss"
#define DATETIME_SQLITE_FORMAT "yyyy-MM-dd hh:mm:ss"

#define USER_ID "USERID"
#define PASSPORT "USERPASSPORT"
#define DEFAULT_MAC "78843C343FCB"
#define EXPIRE_DATE "EXPIREDATE"
#define LAST_VERIFIED "LASTVERIFIED"
#define MY_BIRTH QDate(1985,4,15)

enum GroupPermission {
    GP_None = 0x0,
    GP_Examine = 0x1,
    GP_ExamineStudy = GP_Examine,
    GP_SendStudy = 0x2,
    GP_RemoveStudy = 0x4,
    GP_PrintImage = 0x8,
    GP_CreateReport = 0x10,
    GP_ModifyReport = 0x20,
    GP_VerifyReport = 0x40,
    GP_PrintReport = 0x80,
    GP_ImportStudy = 0x100,
    GP_ExportStudy = 0x200,
    GP_RegisterStudy = 0x400,
    GP_ModifyStudy = 0x800,
    GP_AcquisitImage = 0x1000,
    GP_LocalSettings = 0x2000,
    GP_RemoteServers = 0x4000,
    GP_ProcedureParam = 0x8000,
    GP_UserGroupManagement = 0x10000,
    GP_DatabaseOperation = 0x20000,
    GP_ModifyDiagnosticTemplate = 0x40000,
};
Q_DECLARE_FLAGS(GroupPermissions, GroupPermission)
Q_DECLARE_OPERATORS_FOR_FLAGS(GroupPermissions)


#ifndef GLOBAL_CPP
#define GLOBAL_EXTERN extern
#else
#define GLOBAL_EXTERN
#endif

GLOBAL_EXTERN QString encryptPassword(const QString &pwd);
GLOBAL_EXTERN QString sex2trSex(const QString &sex);
GLOBAL_EXTERN QString trSex2Sex(const QString &trsex);
GLOBAL_EXTERN QTime formatDicomTime(const QString &timeStr);
GLOBAL_EXTERN quint32 generateUserId();
GLOBAL_EXTERN qint32 analyzeDaysSerial(quint64 serial);
GLOBAL_EXTERN qint32 getDaysCount();
GLOBAL_EXTERN void setDaysCount(int count);

struct User{
    QString name;
    QString password;
    QString group;
    QString division;
    QString title;

    User() {
        password = encryptPassword(QString());
    }

    friend QDataStream &operator<<(QDataStream &out, const User &user) {
        return out << user.name << user.password
                   << user.group << user.division << user.title;
    }
    friend QDataStream &operator>>(QDataStream &in, User &user) {
        return in >> user.name >> user.password
                  >> user.group >> user.division >> user.title;
    }
};

struct StringTables {
    StringTables();
    QStringList GroupPermissionStringTable;
    QStringList ScpTypeStringTable;
    QStringList EventTypeStringTable;
    QStringList LogPeriodStringTable;
};

struct Group{
    QString name;
    GroupPermissions permissions;

    friend QDataStream &operator<<(QDataStream &out, const Group &group) {
        quint32 perms = group.permissions;
        return out << group.name << perms;
    }
    friend QDataStream &operator>>(QDataStream &in, Group &group) {
        quint32 perms;
        in >> group.name >> perms;
        group.permissions = GroupPermissions(perms);
        return in;
    }
};

#define DEFAULT_STATION_AET "DRDCM"
#define ACCNUMBER_START "ACCNUMBERSTART"
#define PATIENTID_START "PATIENTIDSTART"
#define REQ_PHYSICIANS "REQPHYSICIANS"
#define REQ_DIVISIONS "REQDIVISIONS"
#define EXAM_BODYPARTS "EXAMBODYPARTS"
#define PER_PHYSICIANS "PERPHYSICIANS"
#define PROCEDURE_IDS "PROCEDUREIDS"
#define PROCEDURE_DESC "PROCEDUREDESC"
#define STATION_AETS "STATIONAETS"
#define STATION_NAMES "STATIONNAMES"
#define PROC_STEP_ID "PROCSTEPID"
#define PROC_STEP_DESC "PROCSTEPDESC"
#define MEDICAL_ALERTS "MEDICALALERTS"
#define PATIENT_ADDR "PATIENTADDR"
#define ADMISSION_IDS "ADMISSIONIDS"
#define BED_NUMBERS "BEDNUMBERS"
#define PATIENT_PHONES "PATIENTPHONES"
#define STUDY_EXPENSES "STUDYEXPENSES"
#define STUDY_DESCRIPTION "STUDYDESCRIPTION"
#define SERIES_DESCRIPTION "SERIESDESCRIPTION"
#define IMAGE_FLAG_FONT "IMAGEFLAGFONT"

struct InstitutionInfo {
    QString name;
    QString addr;
    QString tel;

    friend QDataStream &operator<<(QDataStream &out, const InstitutionInfo &info) {
        return out << info.name << info.addr << info.tel;
    }
    friend QDataStream &operator>>(QDataStream &in, InstitutionInfo &info) {
        return in >> info.name >> info.addr >> info.tel;
    }
};

struct ManufactureInfo {
    QString name;
    QString model;
    QString modality;

    ManufactureInfo() { modality = QString::fromLatin1("DX"); }

    friend QDataStream &operator<<(QDataStream &out, const ManufactureInfo &info) {
        return out << info.name << info.model << info.modality;
    }
    friend QDataStream &operator>>(QDataStream &in, ManufactureInfo &info) {
        return in >> info.name >> info.model >> info.modality;
    }
};

struct StationInfo {
    QString aetitle;
    QString name;
    ushort storeScpPort;
    ushort qrScpPort;
    ushort wlistPort;

    friend QDataStream &operator<<(QDataStream &out, const StationInfo &info) {
        return out << info.aetitle << info.name << info.storeScpPort
                   << info.qrScpPort << info.wlistPort;
    }
    friend QDataStream &operator>>(QDataStream &in, StationInfo &info) {
        return in >> info.aetitle >> info.name >> info.storeScpPort
                  >> info.qrScpPort >> info.wlistPort;
    }
};

enum LogPeriod {
    LP_OneWeek,
    LP_OneMonth,
    LP_OneYear,
    LP_Always,

    LP_PeriodCount,
};

struct DatabaseConfig {
    QString imagePath;
    QString logPath;
    LogPeriod logPeriod;
    DatabaseConfig():logPeriod(LP_OneYear) {}

    friend QDataStream &operator<<(QDataStream &out, const DatabaseConfig &config) {
        quint32 period = config.logPeriod;
        return out << config.imagePath << config.logPath << period;
    }
    friend QDataStream &operator>>(QDataStream &in, DatabaseConfig &config) {
        quint32 period;
        in >> config.imagePath >> config.logPath >> period;
        config.logPeriod = (LogPeriod)period;
        return in;
    }
};

struct CustomizedId {
    bool autoId;
    qint32 digits;
    QString prefix;
    QString suffix;

    CustomizedId() {
        autoId = false;
        digits = 6;
    }

    friend QDataStream &operator<<(QDataStream &out, const CustomizedId &id) {
        return out << id.autoId << id.digits <<
                      id.prefix << id.suffix;
    }
    friend QDataStream &operator>>(QDataStream &in, CustomizedId &id) {
        return in >> id.autoId >> id.digits >>
                     id.prefix >> id.suffix;
    }
};

struct WorklistItem {
    QString accNumber;
    QString patientId;
    QString patientName;
    QString patientSex;
    QDate patientBirth;
    QString patientAge;
    QString medicalAlert;
    QString patientSize;
    QString patientWeight;
    QString patientPhone;
    QString patientAddr;
    QString reqPhysician;
    QString reqProcId;
    QString reqProcDesc;
    QString reqPriority;
    QString schModality;
    QString schStationName;
    QString schStationAE;
    QString schPhysician;
    QDateTime schDateTime;
    QString schProcStepId;
    QString schProcStepDesc;
    QString studyUid;
    QString studyDesc;
};

Q_DECLARE_METATYPE(WorklistItem)

#endif // GLOBAL_H
